#include "standard/MyPool.h"
#include "snetwork/NluHttpRequest.h"    
#include "snetwork/NluEvent.h"
#include "snetwork/WorkerProcess.h"
#include "snetwork/NluEventAccept.h"
#include "snetwork/NluHttpRequest.h"
#include "snetwork/NluHttpResponse.h"
#include "snetwork/NluList.h"
#include "standard/nstring.h"
#include "processlog.h"

    
/*  
     __________________________________________
    /               ___________________________\
   /               /                  __________\
  /               /                  /           \
 |               /                  /             |
  \ nl_request_t \ nl_connection_t | nl_event_t  /
   \              \                 \           /
    \______________\_________________\_________/     
    
    nl_request_t:
        nl_connection_t *connection;
        nl_buf_t *header_in;
        
    nl_connection_t:
        void *data;// nl_request_t *
        int fd;
        nl_event_t *read;
        nl_event_t *write;
        
    nl_event_t:
        void *data; // nl_connection_t *
        u_int eof:1;
        u_int ready:1;
        u_int error:1;    
          
*/ 
            
/**
 * process event
 *   typedef union epoll_data {
 *       void *ptr;
 *       int fd;
 *       __uint32_t u32;
 *       __uint64_t u64;
 *   } epoll_data_t;//保存触发事件的某个文件描述符相关的数据
 *
 *   struct epoll_event {
 *       __uint32_t events;      // epoll event 
 *       epoll_data_t data;      // User data variable
 *   };
 *
 *   其中events表示感兴趣的事件和被触发的事件，可能的取值为：
 *   EPOLLIN：表示对应的文件描述符可以读；
 *   EPOLLOUT：表示对应的文件描述符可以写；
 *   EPOLLPRI：表示对应的文件描述符有紧急的数可读；
 *
 *   EPOLLERR：表示对应的文件描述符发生错误；
 *   EPOLLHUP：表示对应的文件描述符被挂断；
 *   EPOLLET： ET的epoll工作模式；
 */
unsigned int http_event_flags;
int n_epfd;
vecStr n_sendArr;

namespace Sock
{
    CNluEvent *CNluEvent::m_instance = NULL;

    CNluEvent *CNluEvent::instance()
    {
        if (m_instance==NULL) {
            m_instance = new CNluEvent();
        }
        return m_instance;
    }
    
    CNluEvent::CNluEvent()
    {
        
    }
    
     //set block
    int  CNluEvent::setnonblocking(int sockfd) 
    {
#if defined(__GNUC__)
        int flags, s;

        flags = fcntl (sockfd, F_GETFL, 0);
        if (flags == -1) {
            perror ("fcntl");
            return -1;
        }

        flags |= O_NONBLOCK;
        s = fcntl (sockfd, F_SETFL, flags);
        if (s == -1) {
            perror ("fcntl");
            return -1;
        }
        return 0;
        
#elif defined(_MSC_VER)
		u_long i=1;
		ioctlsocket(sockfd,FIONBIO,&i);
		
		return 0;
#endif
    }                   
    
    /**
     * 
     * 申请 ngx_connection_t *c; 
     * 并申请 ngx_event_t *t 并且赋值给ngx_connection_t的 read, write;
     * add the ls_sock to Epoll : epoll_ctl(ADD);
     */
    int CNluEvent::handleInit(nlu_cycle_t *cycle)
    {
        int sockfd, s;
        struct epoll_event ev;
        ssize_t n; 
        char line[MAXLINE]; 
        long int nLeaveByte = -1;
        int request_count   = 0;
        int i = 0;
        struct sockaddr_in serveraddr; 
               
        s = setnonblocking(n_serverfd); //把用于监听的socket设置为非阻塞方式
        if (s == -1) {
            abort ();
        }

        n_epfd = epoll_create1 (0);
        if (n_epfd == -1) {            
            llog( "epoll_create" );
        }
                
        CMyPool my;
        nlu_connection_t *c, *next;
        
        cycle->connections = (nlu_connection_t *)my.nluPcalloc(cycle->pool, 
                                sizeof(nlu_connection_t) * cycle->connection_n );

        if (cycle->connections == NULL) {
            return HTTP_ERROR;
        }

        c = cycle->connections;

        cycle->read_events = (nlu_event_t *)my.nluPcalloc(cycle->pool, 
                                sizeof(nlu_event_t) * cycle->connection_n);
        
        if (cycle->read_events == NULL) {
            return HTTP_ERROR;
        }                        
        
        nlu_event_t *rev = cycle->read_events;
        
        for (i = 0; i < cycle->connection_n; i++) {
            rev[i].closed = 1;
            rev[i].instance = 1;
        }                        
                                        
        
        cycle->write_events = (nlu_event_t *)my.nluPcalloc(cycle->pool, 
                                sizeof(nlu_event_t) * cycle->connection_n);
                                
        if (cycle->write_events == NULL) {
            return HTTP_ERROR;
        }
        
        nlu_event_t *wev = cycle->write_events;
        
        for (i = 0; i<cycle->connection_n; i++) {
            wev[i].closed = 1;
            wev[i].instance = 1;
        }
        
        i = cycle->connection_n;
        next = NULL;
        
        do {
            i--;
            
            c[i].data   = next;
            c[i].read   = &cycle->read_events[i];//nl_event_t
            c[i].write  = &cycle->write_events[i];// nl_event_t
            c[i].fd     = int -1;
            
            next = &c[i];
        } while (i);
        
        //free_connections指向connections的头  
        cycle->free_connections = next;  
        
        //初始化free connection的数目  
        cycle->free_connection_n = cycle->connection_n;  
        
        //获取一个空闲的connection，并设置其file descriptor 
        CNluConnection conn;   
        c = conn.getConnection(n_serverfd);    
        
        ev.data.ptr = c;
        ev.data.fd  = n_serverfd;
        ev.events   = EPOLLIN | EPOLLET;
        s = epoll_ctl (n_epfd, EPOLL_CTL_ADD, n_serverfd, &ev);

        return m_epfd;      
    }
    
    /**
     * event execute
     */
    void CNluEvent::execute(nlu_cycle_t *cycle)
    {
        ssize_t             *cnt_len;  
        socklen_t           clilen; 
        bool                flag = 0;
        struct sockaddr_in  clientaddr;  
        std::string         action;
        int                 nfds, i=0;        
        nlu_connection_t    *c;
        nlu_event_t         *rev, *wev;
        
        try {
            //等待epoll事件的发生
            nfds = epoll_wait(m_epfd, m_event_list, 20, 409600);   
            action.erase();
            
            for (int n=0; n<nfds; n++) {
            
                c = m_event_list[n].data.ptr;
                
                rev = c->read;
                
                if (c->fd == -1) {
                    continue;
                }
                
                if ((m_event_list[n].events & EPOLLERR) ||
                      (m_event_list[n].events & EPOLLHUP) ||
                      (!(m_event_list[n].events & EPOLLIN))) {
                      // An error has occured on this fd, or the socket is not
                      //   ready for reading (why were we notified then?)
                      
                    throw CThrowException("epoll error");
                    close (m_event_list[n].data.fd);
                    
                    return;
	            }
                else if (m_event_list[n].data.fd == n_serverfd) {//监听事件
                
                    CNluEventAccept::instance(NULL)->execute(rev);
                }
                else {
                    //m_parr->action  = &action;                           
                    //m_parr->sockfd  = m_event_list[n].data.fd;
                    
                    //recv data
                    rev->ready  = 1;                    
                    CNluHttpRequest::instance()->execute( rev );
                                        
                    //send data
                    wev = c->write;
                    wev->ready  = 1;
                    CNluHttpResponse::instance()->execute( wev );
                }
            }
        }
        catch (CThrowException e) {
            llog( "Error: %s", e.getMessage().c_str() );
        }
    }
       
    /*
    void CNluEvent::HttpInitEvent(nl_http_request_t *r)
    {        
        CMyPool my;                   
        m_request_pool = my.createPool(100*1024); 
        r = (nlu_http_request_t *) my.nluPcalloc( m_request_pool, sizeof(nlu_http_request_t) );
        
        // create list
        r->out_head              = CNluList::instance()->createList_L();
        r->out                   = r->out_head;                                            
        r->state                 = 0;  
    
        m_parr->sendArr          = &n_sendArr;             
        r->connection->fd        = m_parr->sockfd;                          
        
        r->state                 = 0;                        
        r->header_in             = (http_buf_t*) my.nluPcalloc(m_request_pool, sizeof(http_buf_t));        
        r->header_in->file       = (http_file_t*) my.nluPcalloc(m_request_pool, sizeof(http_file_t));   
        r->header_in->start      = (char*) my.nluPcalloc(m_request_pool, HEADER_INIT_LEN + 1);
        
        r->header_in->pos        = r->header_in->start;                
        r->header_in->last       = r->header_in->start;
        r->header_in->end        = r->header_in->start + sizeof(char) * HEADER_INIT_LEN;
        
        memset(r->header_in->start, 0, sizeof(char)*HEADER_INIT_LEN + 1);        
    }
    
    void CNluEvent::HttpCloseEvent(nl_http_request_t *r)
    {

        CMyPool my;
        
        //释放连接
        shutdown(m_parr->sockfd, SHUT_RDWR);
        close(m_parr->sockfd);
        
        // drop list
        CNluList::instance()->listDrop_L(r->out_head);
                
        my.destoryPool(m_request_pool);
        
        my.destoryPool(c->pool);

    }  
    */    
}
